home *** CD-ROM | disk | FTP | other *** search
- #define NAME "SortCheckX"
- #define REVISION "3"
- #define DISTRIBUTION "(Freeware) "
- #define DATE "17.08.2002"
- #define VERSION "1"
- #define AUTHOR "by Dirk Stöcker <stoecker@epost.de>"
-
- /* Programmheader
-
- Name: SortCheckX
- Author: SDI
- Distribution: PD
- Description: sorts CheckX output by file name to make comparisons possibly
- Compileropts: -
- Linkeropts: -gsi
-
- 1.0 14.08.02 : first version
- 1.1 15.08.02 : added OLDFIX, CRC and OUTFILE
- 1.2 16.08.02 : added buffered Output, optimized
- 1.3 17.08.02 : added secondary filesystem support
- */
-
- #include <proto/dos.h>
- #include <proto/exec.h>
- #include <exec/memory.h>
-
- #define version "$VER: " NAME " " VERSION "." REVISION " (" DATE ") " DISTRIBUTION AUTHOR
- #define PARAM "INFILE/A,OUTFILE,OLDFIX/S,CRC/S"
-
- struct Args {
- STRPTR infile;
- STRPTR outfile;
- ULONG oldfix; /* tries to reduce the differences by fixing older texts */
- ULONG crc;
- };
-
- struct CNode {
- struct CNode *Prev;
- struct CNode *Next;
- struct CNode *Sub;
- struct CNode *Head;
- ULONG BufferPos; /* invalid after Sorting head structure */
- ULONG Size;
- UWORD Flags;
- };
-
- #define FLAG_DISKIMAGE (1<<0)
- #define FLAG_INFOTEXT (1<<1)
- #define FLAG_UNUSED (1<<2)
- #define FLAG_CRC (1<<3)
- #define FLAG_FILESYSTEM (1<<4)
-
- #define OUTBUFSIZE 16384
-
- struct MyOutBuf {
- ULONG CurSize;
- struct ExecBase *SysBase;
- struct DosLibrary *DOSBase;
- BPTR FileHandle;
- UBYTE Buffer[OUTBUFSIZE];
- };
-
- struct MyReplace {
- UWORD Offset;
- UBYTE OldSize;
- UBYTE NewSize;
- };
-
- /* This is a string field of replace strings:
- First comes old, second the new string. Each ends with a '\n'.
- The ReplaceField[] structure below contains offset and element sizes of this
- string field.
-
- Why? Because as result SortCheckX has no Relocs and is very short ;-)
- */
-
- static const UBYTE StringField[] = {
- "CheckX-Error 12: file is empty\n"
- "CheckX-Warning 4: file is empty\n"
-
- "CheckX-Error 4: read or write failed\n"
- "CheckX-Error 4: reading failed\n"
-
- "CheckX-Error 100: not enough memory\n"
- "CheckX-Error 12: not enough memory for full tests\n"
-
- "DMS-Archive\n"
- "DMS (ARCHIVE)\n"
-
- "LhA-Archive\n"
- "LhA (ARCHIVE)\n"
-
- "LhA-SFX-Archive\n"
- "LhA SFX (ARCHIVE)\n"
-
- "LhA-SFX (ARCHIVE)\n"
- "LhA SFX (ARCHIVE)\n"
-
- "LzX-Archive\n"
- "LZX (ARCHIVE)\n"
-
- "Zip-Archive\n"
- "Zip (ARCHIVE)\n"
-
- "ZOO-Archive\n"
- "Zoo (ARCHIVE)\n"
-
- "ZOO (ARCHIVE)\n"
- "Zoo (ARCHIVE)\n"
- };
-
- #ifdef MAKEREPLACEFIELD /* in caseone is to lazy to count by hand ;-) */
- void main(void)
- {
- LONG i = 0, n = 0, last = -1;
-
- do
- {
- if(StringField[i] == '\n')
- {
- if(n++ & 1)
- Printf(/*{*/" %2ld},\n", i-last);
- else
- Printf("{ %3ld, %2ld,"/*}*/, last+1, i-last);
- last = i;
- }
- } while(StringField[++i]);
- Printf("{ 0, 0, 0}\n");
- }
- #else
- static const struct MyReplace ReplaceField[] = {
- { 0, 31, 32},
- { 63, 37, 31},
- { 131, 36, 50},
- { 217, 12, 14},
- { 243, 12, 14},
- { 269, 16, 18},
- { 303, 18, 18},
- { 339, 12, 14},
- { 365, 12, 14},
- { 391, 12, 14},
- { 417, 14, 14},
- { 0, 0, 0}
- };
-
- static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s);
- static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase);
- static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf);
-
- ULONG start(void)
- {
- struct DosLibrary *DOSBase;
- struct ExecBase *SysBase = (*((struct ExecBase **) 4));
-
- { /* test for WB and reply startup-message */
- struct Process *task;
- if(!(task = (struct Process *) FindTask(0))->pr_CLI)
- {
- WaitPort(&task->pr_MsgPort);
- Forbid();
- ReplyMsg(GetMsg(&task->pr_MsgPort));
- return RETURN_FAIL;
- }
- }
-
- if((DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
- {
- struct Args args;
- struct RDArgs *rda;
-
- args.oldfix = args.crc = 0;
- args.outfile = 0;
- if((rda = ReadArgs(PARAM, (LONG *) &args, 0)))
- {
- BPTR fh;
- if(args.crc)
- args.crc = FLAG_CRC;
- if((fh = Open(args.infile, MODE_OLDFILE)))
- {
- struct FileInfoBlock *fib;
-
- if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
- {
- if(ExamineFH(fh, fib))
- {
- STRPTR mem = version; /* removed by optimizer */
- if((mem = (STRPTR) AllocMem(fib->fib_Size+1, 0)))
- {
- mem[fib->fib_Size] = '\n';
- if(Read(fh, mem, fib->fib_Size) == fib->fib_Size)
- {
- /* This does no error checking and will produce total crap
- with non-CheckX files, but should make no crash or other
- dangerous error. */
- ULONG i, depth1 = 0, depth2;
- /* depth 1 --> number of '*', depth2 --> number of - types */
- struct CNode *cbuf, *cbufp, *curnode;
-
- /* depth2 is a short time used to count number of lines */
- for(i = depth2 = 0; i < fib->fib_Size; ++i)
- {
- if(mem[i] == '\n' && mem[i+1] != ' ')
- ++depth2;
- }
- depth2 += 5; /* security */
-
- if((cbuf = AllocVec(depth2*(sizeof(struct CNode))+sizeof(struct MyOutBuf), MEMF_CLEAR)))
- {
- struct MyOutBuf *outbuf = (struct MyOutBuf *) (cbuf+depth2);
-
- outbuf->FileHandle = Output();
- outbuf->DOSBase = DOSBase;
- outbuf->SysBase = SysBase;
- if(!args.outfile || (outbuf->FileHandle = Open(args.outfile, MODE_NEWFILE)))
- {
- depth2 = i = 0;
-
- while(i < fib->fib_Size) /* skip the start texts */
- {
- if(!mystrncmp("Virus-Checking", mem+i, 14))
- {
- while(mem[i++] != '\n')
- ;
- }
- else if(!mystrncmp("The xvs.library", mem+i, 15))
- {
- while(mem[i++] != '\n')
- ;
- }
- else if(!mystrncmp("Your system memory", mem+i, 18))
- {
- while(mem[i++] != '\n')
- ;
- }
- else
- break;
- }
-
- cbufp = cbuf;
-
- /* the master header, no bytes */
- curnode = cbufp++;
- cbufp->Head = curnode;
- curnode->Sub = cbufp;
-
- /* the first line */
- curnode = cbufp++;
- curnode->BufferPos = i;
- while(mem[i++] != '\n')
- ;
-
- while(i < fib->fib_Size && mem[i] != '\n'
- && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- /* this is either the empty line or file end */
- {
- ULONG d, i2 = 0;
-
- if(mem[i] != ' ') /* if ' ' attach a type line to current type */
- {
- if(args.crc)
- {
- for(i2 = 0; i2 < 9 && mem[i+i2] != '\n'; ++i2)
- ;
- if(i2 != 9) i2 = 0;
- }
-
- if(!curnode->Size)
- curnode->Size = i-curnode->BufferPos;
- for(d = 0; mem[i+i2+d] == '*'; ++d)
- ;
- if(d > depth1) /* a subtype */
- {
- cbufp->Head = curnode;
- cbufp->BufferPos = i;
- cbufp->Flags = args.crc;
- curnode->Sub = cbufp;
- curnode = cbufp++;
- ++depth1;
- }
- else if(d == depth1) /* equal or subtype 2 */
- {
- if(!mystrncmp("--infotext", mem+i+i2+d, 10))
- {
- if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- {
- cbufp->Prev = curnode;
- cbufp->Head = curnode->Head;
- cbufp->BufferPos = i;
- cbufp->Flags = FLAG_INFOTEXT|args.crc;
- curnode->Next = cbufp;
- curnode = cbufp++;
- }
- else
- {
- cbufp->Head = curnode;
- cbufp->BufferPos = i;
- cbufp->Flags = FLAG_INFOTEXT|args.crc;
- if(curnode->Sub)
- {
- for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
- ;
- curnode->Next = cbufp;
- cbufp->Prev = curnode;
- }
- else
- curnode->Sub = cbufp;
- curnode = cbufp++;
- ++depth2;
- }
- }
- else if(!mystrncmp("-disk image", mem+i+i2+d, 11))
- {
- if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- {
- cbufp->Prev = curnode;
- cbufp->Head = curnode->Head;
- cbufp->BufferPos = i;
- cbufp->Flags = FLAG_DISKIMAGE|args.crc;
- curnode->Next = cbufp;
- curnode = cbufp++;
- }
- else
- {
- cbufp->Head = curnode;
- cbufp->BufferPos = i;
- cbufp->Flags = FLAG_DISKIMAGE|args.crc;
- if(curnode->Sub)
- {
- for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
- ;
- curnode->Next = cbufp;
- cbufp->Prev = curnode;
- }
- else
- curnode->Sub = cbufp;
- curnode = cbufp++;
- ++depth2;
- }
- }
- else /* new equal type */
- {
- if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- {
- --depth2;
- curnode = curnode->Head;
- SortSubTree(curnode, mem, SysBase);
- }
- cbufp->Prev = curnode;
- cbufp->Head = curnode->Head;
- cbufp->BufferPos = i;
- cbufp->Flags = args.crc;
- curnode->Next = cbufp;
- curnode = cbufp++;
- }
- }
- else /* leave that level depth1-d times, take care for depth2 and sizes */
- {
- /* set sizes! */
- while(depth1 > d || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- {
- if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- --depth2;
- else
- --depth1;
- curnode = curnode->Head;
- SortSubTree(curnode, mem, SysBase);
- }
- continue; /* parse this again */
- }
- }
- else
- {
- for(d = 0; mem[i+d] == ' '; ++d)
- ;
- if(args.crc) d -= 9;
- if(d <= depth1 || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- {
- if(!curnode->Size)
- curnode->Size = i-curnode->BufferPos;
- while(depth1 >= d)
- {
- if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
- --depth2;
- else
- --depth1;
- curnode = curnode->Head;
- SortSubTree(curnode, mem, SysBase);
- }
- cbufp->Prev = curnode;
- cbufp->Head = curnode->Head;
- cbufp->BufferPos = i;
- cbufp->Flags = FLAG_FILESYSTEM|args.crc;
- curnode->Next = cbufp;
- curnode = cbufp++;
- }
-
- }
- while(mem[i++] != '\n')
- ;
- }
- if(i > fib->fib_Size)
- i = fib->fib_Size;
- if(!curnode->Size)
- curnode->Size = i-curnode->BufferPos;
- while(curnode->Head)
- {
- curnode = curnode->Head;
- SortSubTree(curnode, mem, SysBase);
- }
-
- /* curnode now represents a complete tree, where each entry starts
- with a filename (or disk image, infotext) and may have additional
- texts after the first line. For a file information tree only use
- first line (except for filesystem which has no name)!
- */
- if(curnode->BufferPos && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- MyOutput(mem, curnode->BufferPos, outbuf);
- cbufp = cbuf->Sub;
- while(cbufp && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- {
- if(args.oldfix)
- {
- STRPTR buf, bufend, beg;
-
- buf = mem+cbufp->BufferPos;
- bufend = buf+cbufp->Size;
- while(buf < bufend)
- {
- beg = buf;
- if(*buf == ' ')
- {
- const struct MyReplace *mr = ReplaceField;
-
- while(*buf == ' ')
- ++buf;
- MyOutput(beg, buf-beg, outbuf);
- beg = buf;
-
- while(mr->OldSize && mystrncmp(buf,
- ((STRPTR)StringField)+mr->Offset, mr->OldSize))
- ++mr;
- if(mr->OldSize)
- {
- MyOutput(((STRPTR)StringField)+mr->OldSize+mr->Offset,
- mr->NewSize, outbuf);
- buf += mr->OldSize;
- continue;
- }
- }
- while(buf < bufend && *(buf++) != '\n')
- ;
- MyOutput(beg, buf-beg, outbuf);
- }
- }
- else
- MyOutput(mem+cbufp->BufferPos, cbufp->Size, outbuf);
-
- if(cbufp->Sub) cbufp = cbufp->Sub;
- else if(cbufp->Next) cbufp = cbufp->Next;
- else
- {
- cbufp = cbufp->Head;
- while(cbufp && !cbufp->Next)
- cbufp = cbufp->Head;
- if(cbufp) cbufp = cbufp->Next;
- }
- }
- if(i < fib->fib_Size && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- MyOutput(mem+i, fib->fib_Size-i, outbuf);
- if(outbuf->CurSize)
- Write(outbuf->FileHandle, outbuf->Buffer, outbuf->CurSize); /* Flush buffer */
- if(args.outfile)
- Close(outbuf->FileHandle);
- }
- FreeVec(cbuf);
- }
- }
- FreeMem(mem, fib->fib_Size+1);
- }
- }
- FreeDosObject(DOS_FIB, fib);
- }
- if(fh)
- Close(fh);
- }
-
- FreeArgs(rda);
- }
-
- CloseLibrary((struct Library *) DOSBase);
- }
- return 0;
- }
-
- #define DOSBase outbuf->DOSBase
- #define SysBase outbuf->SysBase
- static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf)
- {
- ULONG maxs;
- do
- {
- maxs = OUTBUFSIZE - outbuf->CurSize;
- if(maxs > size)
- maxs = size;
- CopyMem(mem, outbuf->Buffer+outbuf->CurSize, maxs);
- outbuf->CurSize += maxs;
- mem += maxs;
- size -= maxs;
- if(outbuf->CurSize == OUTBUFSIZE)
- {
- Write(outbuf->FileHandle, outbuf->Buffer, OUTBUFSIZE);
- outbuf->CurSize = 0;
- }
- } while(size);
- }
- #undef SysBase
- #undef DOSBase
-
- static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s)
- {
- while(s && *a && *a == *b)
- {
- ++a; ++b; --s;
- }
- return s ? (*a - *b) : 0;
- }
-
- #define mytolower(a) ((a >= 'A' && a <= 'Z') || (a >= 0xC0 && a <= 0xDE) ? a+32 : a)
-
- /* Sorts case insensitive, when equal the case is used for sorting,
- if still equal the order is undefined! */
- static LONG MyNodeComp(struct CNode *list, struct CNode *new, STRPTR mem)
- {
- STRPTR l, n;
- LONG d, e;
-
- if(list->Flags & (FLAG_UNUSED|FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM)) /* always greater */
- return 1000;
-
- l = mem+list->BufferPos;
- n = mem+new->BufferPos;
- if(new->Flags & FLAG_CRC)
- {
- for(d = 0; d < 9 && l[d] != '\n' && n[d] != '\n'; ++d)
- ;
- if(d == 9)
- {
- l += d;
- n += d;
- }
- }
- d = 0;
-
- while(!(e = (mytolower(*l) - mytolower(*n))) && *l != '\n')
- {
- if(*l != *n && !d) /* sort by case if equal */
- d = *l-*n;
- ++l; ++n;
- }
- return (e ? e : d);
- }
-
- static struct CNode *InsertFront(struct CNode *list, struct CNode *newnode)
- {
- struct CNode *next;
-
- if((next = newnode->Next))
- next->Prev = 0;
-
- newnode->Next = list;
- if((newnode->Prev = list->Prev))
- newnode->Prev->Next = newnode;
- list->Prev = newnode;
-
- return next;
- }
-
- static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase)
- {
- struct CNode *oldlist, *list, dummylast;
- /* list = list of new nodes */
- /* oldlist = list of old nodes */
-
- if(!(oldlist = curnode->Sub))
- return;
- dummylast.Prev = dummylast.Next = 0;
- dummylast.Flags = FLAG_UNUSED;
- list = &dummylast; /* the dummy entry is to make work easier and faster */
-
- while((oldlist = InsertFront(list, oldlist)) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- {
- if(oldlist->Flags & (FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM))
- list = &dummylast; /* insert at end - in correct (unsorted) order */
- else if(MyNodeComp(list, oldlist, mem) <= 0)
- {
- list = list->Next;
- while(MyNodeComp(list, oldlist, mem) <= 0 && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- list = list->Next;
- }
- else /* insert before this */
- {
- while(list->Prev && (MyNodeComp(list->Prev, oldlist, mem) > 0) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
- list = list->Prev;
- }
- }
- while(list->Prev)
- list = list->Prev;
-
- dummylast.Prev->Next = 0; /* remove last entry */
- curnode->Sub = list; /* the start of list */
- }
- #endif /* MAKEREPLACEFIELD */
-